package model.market;

import java.util.ArrayList;
import java.util.List;

import model.util.stats.RegressionCalc.RegressionResult;

public class Position {

	private int startPeriod = 0;

	public void setStartPeriod(int start) {
		startPeriod = start;
	}

	/**
	 * AM: note that marketinfo must be up to date, i.e. market return etc.
	 * 
	 * @param manager
	 * @param marketInfo
	 */
	public double getBeta(double[] marketPrices, double[] assetBetas) {
		double portfolioAssetVal=getNominalAssetValue(marketPrices);
		if(portfolioAssetVal==0){
			return 0;
		}
		double beta = 0;
		for (int asset = 0; asset < assetBetas.length; asset++) {
			double weighting = getExecutedQuantity(asset) * marketPrices[asset] / portfolioAssetVal;
			
			double assetBeta = assetBetas[asset];
			beta += assetBeta * weighting;
		}
		double assetWeighting = portfolioAssetVal/(getCash() + portfolioAssetVal);
		if(Double.isNaN(assetWeighting)){
			return 0; 
		}
		beta = beta * (assetWeighting);
		return beta;
	}

	public Position(double cash) {
		this.cash = cash;
		originalCash = cash;
	}

	private List<Trade> executedTrades = new ArrayList<Trade>();
	private double cash;
	private double originalCash;

	public double getOriginalCash() {
		return originalCash;
	}

	public List<Trade> getExecutedTrades() {
		return executedTrades;
	}

	public void setExecutedTrades(List<Trade> executedTrades) {
		this.executedTrades = executedTrades;
	}

	public void addTrade(Trade trade) {
		executedTrades.add(trade);

		if (trade.getDirection() == Trade.SELL) {
			if (Double.isNaN(trade.getExecutedQuantity()) || Double.isNaN(trade.getExecutedPrice())) {
				throw new RuntimeException("NaN alert: " + trade.getExecutedQuantity() + " " + trade.getExecutedPrice());
			}
			cash += trade.getExecutedPrice() * trade.getExecutedQuantity();

		} else {
			if (Double.isNaN(trade.getExecutedQuantity()) || Double.isNaN(trade.getExecutedPrice())) {
				throw new RuntimeException("NaN alert: " + trade.getExecutedQuantity() + " " + trade.getExecutedPrice());
			}
			cash -= trade.getExecutedPrice() * trade.getExecutedQuantity();
		}

	}

	public int getExecutedQuantity(int assetReference) {

		int count = 0;
		for (int i = 0; i < executedTrades.size(); i++) {
			Trade trade = executedTrades.get(i);
			if (trade.getAssetReference() != assetReference) {
				continue;
			}
			int tradeQuantity = trade.getExecutedQuantity();
			if (trade.getDirection() == Trade.SELL) {
				tradeQuantity = -tradeQuantity;
			}
			count += tradeQuantity;
		}
		return count;
	}

	
	
	/**
	 * Note we dont allow short positions. Short positions would have an impact on these sorts of calcs.
	 * @param marketPrices
	 * @return
	 */
	public double getNominalAssetValue(double[] marketPrices) {
		int assetRef=0;
		double ret=0;
		for(double marketPrice:marketPrices){
			ret+=marketPrice*getExecutedQuantity(assetRef);
			
			assetRef++;
		}
		return ret;
	}
	
	//AM: remnants from when shorting was allowed..
	//
//	public double getNominalAssetValue(double[] marketPrices) {
//		double ret = 0;
//		for (int tradeCount = 0; tradeCount < executedTrades.size(); tradeCount++) {
//			Trade trade = executedTrades.get(tradeCount);
//	
//			double tradeValue = getTradeValue(marketPrices[trade.getAssetReference()], trade);
//	
//			ret += tradeValue;
//	
//		}
//		return ret;
//	}
//	
//	/**
//	 * 
//	 * @param marketPrice
//	 * @param trade
//	 * @return
//	 */
//	public double getTradeValue(double marketPrice, Trade trade) {
//		int quantity = trade.getExecutedQuantity();
//		double tradeValue = 0;
//		if (trade.getDirection() == Trade.BUY) {
//			tradeValue = (marketPrice) * quantity;// ((marketPrice)-trade.getExecutedPrice())*quantity;
//	
//		} else {
//			// Profit
//			tradeValue = (trade.getExecutedPrice() - (marketPrice)) * quantity;
//			// Cash..
//			tradeValue -= trade.getExecutedPrice() * quantity;
//		}
//		return tradeValue;
//	}
	

	/**
	 * allows us to determine worth at a particular point in time..
	 * 
	 * @param marketPrice
	 * @param period -
	 *            first period is zero.
	 * @return
	 */
	public double getWorth(double[] marketPrices) {
		double worth = 0;
		worth += cash;
		worth+=getNominalAssetValue(marketPrices);
		return worth;
	}

	
	
	public double getCash() {
		return cash;
	}

	public void addCash(double d) {
		if (Double.isNaN(d)) {
			throw new RuntimeException("Cash is not a number? ");
		}

		cash += d;
	}

	public void addPosition(Position pos) {
		cash += pos.cash;
		executedTrades.addAll(pos.executedTrades);
	}

}


